你的代码会说话吗?(下)
代码不讲真话的直接后果是所有人被误导了,然后做了一件错误的事情,不自知地将错就错,让错误越陷越深,最后浪费宝贵的时间。可不讲真话,编写代码的人又不是故意的,也万万不可上纲上线,袁帅秉着内训师作为知识沉淀者和文化传播者角色的原则,借助教育代码的机会组织了一次部门内部的闲聊会,并美其名曰:Clean Code交流会。本文分为上下两篇,此为下篇,上篇内容请参见你的代码会说话吗?(上)
周五,是一个心情放松的日子,距离年会过去也快整整一周了。袁帅也趁此机会召集了团队的几名开发在线学习系统的小伙伴来码聊。看起来是一次不经意的安排,其实他早有准备。
会议室里,袁帅开门见山:“最近跟一个北美 BP 在协商给他们大客户团队的骨干成员强化敏捷工程实践,现在很多部门内训有一套敏捷工程实践课程。但是很有意思的是,这个BP跟我线上会议沟通时,从来不一步到位,总会在微信上再跟我发文字再解释一遍,也不知道是我看着傻,还是她认为我痴呆。”
大家被袁帅这开场给逗乐了,抛给他好奇的目光。
“没讲清楚呗,再给你讲一遍。”清扬一副若无其事的样子。
“嗯,她担怕开会没讲清楚,想再跟我解释一遍,而且每次微信上的留言比她会议上讲的要更明确更具体。所以,后来慢慢地我习惯在会议上忽视她提供的信息,直接看她的微信留言。”
“那你们还干嘛开会呀,不是白费时间吗!” 万正义直率地补充道。“可是,有时候她在后续的会议上又把之前留言的内容给更新了却忘了再给我留言。” 袁帅表现得无辜。
“所以,你仍然按照微信留言的信息,结果误解了真实的意思!” 清扬有抢答道。
“嗐,你还别提,我最近都没跟活人打交道,也总是遇到这种烦恼。” 刘欢欢一脸满腹牢骚的表情。
“是嘛,说来听听?”袁帅故作惊讶般试探道。
“注释啊,最近看到一些代码的注释,本来不看注释花点时间琢磨琢磨代码,还能搞清楚代码在做什么,可是有时想走捷径,瞅了眼注释,发现注释是错的,骗的我团团转,被谎言带节奏真不爽!” 欢欢打趣地补充。
“对的,这就跟我提到的那个BP类似,总习惯加一些修饰,本来初心是好的,是想解释得更清楚,可是修饰只是一种补充信息,有时候原始信息变更了,修饰却没有跟着更新,不但没有起到修饰作用,反而会误导别人,很耽误事儿!” 袁帅同情地回复了正义。
“说白了,还是没有想清楚,代码要做什么事情,然后觉得需要通过注释去解释一下,后面代码改了,大概率是不会修改注释的。” 正义总是话里充满着正义。
“可能是使用中文注释读起来更顺畅吧,因为代码不太好用中文命名”。程晓娜以理解的口吻弱弱地补充了一句。
袁帅突然陷入了沉思,脑海里浮现出两个画面:
他曾经辅导过的某些程序员,因为英语功底不好,很难将中文翻译成恰当的英文,这在一定程度限制了他们,即便有翻译工具的辅助。
有一次为了给一个方法起名字,他跟三个10多年的工作经验的技术Leader一起讨论了10来分钟,最后才搞定,但大家很开心。
“为什么要写注释啊?代码自解释不香吗?只有代码没法自解释的时候才用一下注释还能接受!” 正义越发正义起来。
“可有时方法太长了,做的事情比较多,每一段相关的代码用注释说明一下在做什么也不是不可取的吧?”清扬见缝插针地抛了个问题。
“Talk is cheap,show me the code!”袁帅展示了准备好的代码:
“2分钟时间,大家先仔细阅读这几段段代码,把你看到的问题和建议改进措施发到咱们的讨论群里哈。”
5分钟后,袁帅把所有人的答案汇总起来:
示例1:类上的注释完全没必要,因为VCS工具能够很好地做记录。
示例1:构造方法方法上的注释是冗余的,构造器本身就能表达构造对象,参数也能表达传入的东西。
示例2:方法的注释的确起到了解释作用,但是让方法自解释更香:更名为listByStatus后干掉注释。
紧接着,袁帅再抛出一个复杂的示例:
大家花了3分钟找出问题:
示例3:方法太长,中间分段注释解释做什么的可以抽取方法,然后将注释转换成方法名来表达意图。
示例3:printReceipt方法内打印日期和客户忠诚度注释过期了,实际上代码被注释掉了。
示例3:printReceipt方法内那个税率写的是15%,而实际用的10%,误导读者。
“注释并不是一无是处,毕竟那谁讲过 -- 「存在即合理」。注释存在这么多年,而且很多地方咱们也看到过。” 袁帅又恢复了主持人的状态。
“有啊,「开放API文档」到处都是API注释,而且还要写好看了。”
“最近有几段代码实在有些实现的难言之隐,我必须通过注释来解释一下。”
“嗯,我刚碰到过「法律版本信息」的一些注释,白纸黑字的注释声明不能少。”
“魔术代码可以注释一下啊,比如复杂的邮件正则表达式:/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
”
袁帅对最后这一个补充有点感兴趣,趁机提了个问题:“魔术代码除了注释,还有更好的方式吗?”
“引入「解释性变量」啊,比如:emailMatcher。”清扬这次临场发挥反应很快。
“大家怎么看待「TODO | FIXME」这种注释呢?”清扬紧接着有抛了个问题。
“不提倡,虽然它能帮助我们在本地记录一些代办列表,但尽可能及时处理完这些任务,将注释清理掉,别提交到生产上。”正义的声音覆盖了全场。
袁帅朝清扬和正义点了个大拇指赞,简单做了个总结:“有一些场景需要注释的,当我们想要添加注释的时候,我们首先应该想想代码能否做到自解释?”
在收拾电脑之际,他脑海里浮现出Uncle Bob关于注释的一句话:
“注释不同于《辛德勒的名单》。它们不是‘纯善的’。事实上,注释充其量是一种必要的恶。”
-- Robert C.Martin
老马(Martin Fowler)的博客上有一句话:“There are only two hard things in Computer Science: cache invalidation and naming things.”。这句话不是老马本人讲的,老马表示很认同,袁帅也很认同,而且越来越信。
距离上一次的 Clean Code 交流会过去刚好一周,今天天气格外晴朗,清扬饶有兴致喊上袁帅去楼底下新开的小餐馆炒俩菜。
两人来到餐厅刚坐定,袁帅手机微信语音响起来,是隔壁团队的 TL 石彪,想约他聊聊上次TDD工作坊后大家的落地情况和疑惑。
清扬伸手递过菜单示意袁帅点个菜,他只说了个“青菜”继续跟石彪聊了起来。清扬找了好一会也没找到“青菜”,见袁帅聊得投入,就帮他点了个绿色的白灼生菜,还点了只清蒸桂花鱼,外加两份单人份的土鸡汤和米饭。
10分钟后,“青菜” 上来了,袁帅吃了两口觉着不对劲:“咦,我点的是青菜啊,怎么上了个生菜呢?”
“大哥,我尽力了,菜单没有找到“青菜”,就点了个这咯。” 清扬一脸无辜。
“哦,我们那有一种叫“上海青”的蔬菜,平时我们都叫青菜。” 袁帅说完立即意识到自己现在身在北方,这边的叫法跟老家可能不一样。
“哈哈,我们西安把青菜理解成绿色的蔬菜~” 清扬说着就递过来菜单。
看到 “清炒油菜”,袁帅心里开始琢磨着:“不同地区(上下文),对同一个东西的叫法是可能不一样的,如果切换了地区,自己还沿用原来地区的叫法,很可能造成困惑和误解。”
“不同行业,不同领域,不同上下文,同物可不同名。你常常给我讲写代码的时候要特别注意这一点,开发哪个行业的系统,就应该使用该行业的业务语言,有利于统一语言,交流起来效率会高很多,而且代码跟业务相匹配,更容易理解。” 清扬猜到了袁帅在琢磨什么,替他做了一个总结。
“你们的清蒸桂花鱼,请慢用!” 服务员把香气四溢的鱼端到桌上,这是袁帅小时候特别喜欢的一道菜,他开心地拿起筷子正要去夹鱼尾:“咦,刚才服务员叫它清蒸桂花鱼?” “对啊,桂花鱼,清蒸的,营养健康,色香味俱全。”清扬麻利地回应着。
袁帅拿起菜单看了一眼,嘴里边嘟囔边若有所悟地点头着:“在我老家这个菜叫「清蒸鳜鱼」。”
清扬瞥了他一眼,作摇头叹息状伸手去夹鱼,开心地吃了起来。“小鬼厉害啊,竟然点了我最喜欢的鱼,这顿饭我请了哈~” 袁帅这次快速从他的菜品命名的思绪中跳脱出来。
吃完饭回来,袁帅喊上清扬去看看隔壁石彪的团队在做的Code Review,见到大屏幕上的代码:
“小豹,这个FlyLine
是指飞行路线吗?” 石彪小心翼翼地问。
“嗯,是这个意思!”
“你在IDE搜一下【Route】” 只见小豹比较娴熟地用快捷键定位到一个Route
类:
看到这个类,小豹快速在正开着的Google翻译框里查到【Route:航线】。
“你打开Trello卡上的【航空术语】那张卡片上的有个航空术语链接。你打开页面敲关键字【航线】进行搜索。”石彪见小豹下意识挠着头不知所措,就进一步给了提示。
石彪10秒钟的指尖操作后,大屏幕上将页面展示出来:
“小豹刚来,对这些航空行业术语不熟悉可以理解,我提前给大家分享一条我的经验:入行说行话,既然咱们在开发航空系统,我们就要讲航空行话。” 石彪刻意扫视了所有在场的小伙伴,继续说道:“那怎么学会这些行话呢,翻译工具是一个好助手,但有时它也会不灵,咱们团队一直有在维护了一套专门的术语,上周我刚把它开发成Web版部署在内网服务器上了,咱们随时可以在上面检索术语哈。”
石彪说完,小豹立刻示意结对的小伙伴在卡片上记下了一个Action:[ 更换Flight类中引用Flyline --> Route ]。
如果说「域冗余」、「码尾禅」、「层错综」这些是代码在沟通表达时的 偏形,那「伪修饰」、「行外话」这些就属 走神 了,而这些貌合神离的假话更容易蛊惑人心。
写代码本没什么大事,努力打磨这五点,时刻审视代码,时刻自省,软件的可理解性可提升至少90%,没错就是很高。
- 相关阅读 -你的代码会说话吗?(上)
Thoughtworks x 哈佛商业评论|超越技术,利用 Data Mesh 创造业务价值